package org.chen.gateway.config;

import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.server.ServerWebExchange;

//@Configuration
public class SaTokenConfigure {
    // 注册 Sa-Token全局过滤器
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter()
                // 拦截地址
                .addInclude("/**")
                // 开放地址
                .addExclude("/apis/auth/login")
                .addExclude("/apis/auth/logout")
                .addExclude("/apis/doc.html")
                .addExclude("/v3/api-docs/**")
                .addExclude("/apis/auth/refresh-token")
                // 鉴权方法：每次访问进入
                .setAuth(obj -> {
                    // 登录校验 -- 拦截所有路由，并排除/auth/doLogin 用于开放登录
                    StpUtil.checkLogin();
                })
                // 异常处理方法：每次setAuth函数出现异常时进入
                .setError(e -> {
                    // 设置错误返回格式为JSON
                    ServerWebExchange exchange = SaReactorSyncHolder.getContext();
                    exchange.getResponse().getHeaders().set("Content-Type", "application/json; charset=utf-8");
                    // 设置HTTP状态码为401
                    exchange.getResponse().setStatusCode(org.springframework.http.HttpStatus.UNAUTHORIZED);

                    // 根据异常类型返回不同的错误信息
                    String message = "认证失败";
                    int code = 401;

                    if (e instanceof NotLoginException) {
                        NotLoginException notLoginException = (NotLoginException) e;
                        switch (notLoginException.getType()) {
                            case NotLoginException.NOT_TOKEN:
                                message = "未提供Token";
                                break;
                            case NotLoginException.INVALID_TOKEN:
                                message = "Token无效";
                                break;
                            case NotLoginException.TOKEN_TIMEOUT:
                                message = "登录信息已过期，请重新登录";
                                break;
                            case NotLoginException.BE_REPLACED:
                                message = "您的账户已在另一台设备上登录";
                                break;
                            case NotLoginException.KICK_OUT:
                                message = "已被系统强制下线";
                                break;
                            default:
                                message = "登录状态异常，请重新登录";
                        }
                    } else {
                        message = e.getMessage();
                    }

                    return SaResult.error(message).setCode(code);
                })
                .setBeforeAuth(obj -> {
                    // ---------- 设置跨域响应头 ----------
                    SaHolder.getResponse()
                            // 允许指定域访问跨域资源
                            .setHeader("Access-Control-Allow-Origin", "*")
                            // 允许所有请求方式
                            .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                            // 有效时间
                            .setHeader("Access-Control-Max-Age", "3600")
                            // 允许的header参数
                            .setHeader("Access-Control-Allow-Headers", "*");

                    // 如果是预检请求，则立即返回到前端
                    SaRouter.match(SaHttpMethod.OPTIONS)
                            .free(r -> System.out.println("--------OPTIONS预检请求，不做处理"))
                            .back();
                });

    }



}
